package com.android.bitmapfun.util;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;

import com.android.bitmapfun.util.ImageCache.ImageCacheParams;
import com.linkrenhe.frame.http.TokenCallback;
import com.linkrenhe.frame.http.Tools;
import com.sczmgk.hotline_pzh.utils.BitmapUtils;
import com.sczmgk.hotline_pzh.utils.MyLog;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;

/**
 * 图片提取工具
 * @author bo
 *
 */
public class MyImageFetcher extends ImageFetcher {

	// Set memory cache to 25% of app memory
	private static final float MEM_CACHE_SIZE_PERCENT = 0.15f;
	private static final String IMAGE_HEAD_ICON_CACHE_DIR = "thumbs";
	private static final String TAG = "PAImageFetcher";

	private ImageCacheParams headIconCacheParams;

	private static MyImageFetcher mPAImageFetcher;

	private TokenCallback mTokenCallback;

	/**
	 * 构造方法
	 * @param context
	 * @param tokenCallback
	 */
	private MyImageFetcher(Context context, TokenCallback tokenCallback) {
		super(context);
		mTokenCallback = tokenCallback;
		headIconCacheParams = new ImageCacheParams(context,
				IMAGE_HEAD_ICON_CACHE_DIR);
		headIconCacheParams.setMemCacheSizePercent(MEM_CACHE_SIZE_PERCENT);
		addImageCache(headIconCacheParams);
	}

	/**
	 * 初始化
	 * 
	 * @param context
	 * @param tokenCallback
	 */
	public static void init(Context context, TokenCallback tokenCallback) {
		if (mPAImageFetcher == null) {
			mPAImageFetcher = new MyImageFetcher(context, tokenCallback);
		}
	}

	/**
	 * 单例
	 * @return
	 */
	public static MyImageFetcher getInstance() {
		return mPAImageFetcher;
	}

	/**
	 * 通过url 取得路径
	 * @param url
	 * @return
	 */
	public String getLocalPathByUrl(String url) {
		if (TextUtils.isEmpty(url)) {
			return null;
		}
		String key = ImageCache.hashKeyForDisk(url);
		File file = new File(mHttpDiskCache.getDirectory(), key + "."
				+ DISK_CACHE_INDEX);
		if (file != null && file.exists()) {
			return file.getAbsolutePath();
		}
		if (file != null && file.exists()) {
			return file.getAbsolutePath();
		}
		return null;
	}

	/**
	 *取得图片
	 * @param data
	 * @return
	 */
	public Bitmap getThumbsBitmap(LoadImage data) {
		BitmapDrawable drawable = mImageCache.getBitmapFromMemCache(data.getCacheKey());
		if (drawable != null) {
			return drawable.getBitmap();
		}
		Bitmap bitmap = mImageCache.getBitmapFromDiskCache(data.getCacheKey());
		if (bitmap != null) {
			mImageCache.addBitmapToMemCache(data.getCacheKey(),
					new RecyclingBitmapDrawable(mResources, bitmap));
		}
		return bitmap;
	}

	@Override
	protected Bitmap processBitmap(LoadImage data, Callback callback) {
		Bitmap bitmap = null;
		try {
			synchronized (mHttpDiskCacheLock) {
				// Wait for disk cache to initialize
				while (mHttpDiskCacheStarting) {
					try {
						mHttpDiskCacheLock.wait();
					} catch (InterruptedException e) {
					}
				}
				bitmap = processLocalCache(data);
				if (data instanceof LoadImageFile) {
					bitmap = processFileBitmap((LoadImageFile) data);
				} else if (data instanceof LoadImageThumb) {
					bitmap = processThumbBitmap((LoadImageThumb) data);
				} else {
					if (data.isDownloadAvailable()) {
						bitmap = processUrlBitmap((LoadImageUrl) data, callback);
					} else {
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} catch (OutOfMemoryError e) {
			e.printStackTrace();
		}
		return bitmap;
	}

	/**
	 * 是否有缓存图片
	 */
	@Override
	protected boolean hasLocalCache(LoadImageUrl data) {
		try {
			if (mHttpDiskCache != null && !mHttpDiskCacheStarting) {
				String cacheKey = data.getSourceCacheKey();
				final String key = ImageCache.hashKeyForDisk(cacheKey);
				final DiskLruCache.Snapshot snapshot = mHttpDiskCache.get(key);
				if (snapshot != null) {
					return true;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	private Bitmap processThumbBitmap(LoadImageThumb data) {
		Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(data
				.getApplication().getContentResolver(), data.getSourceId(),
				data.getTyle(), null);
		return bitmap;
	}

	private Bitmap processLocalCache(LoadImage data) {
		FileInputStream fileInputStream = null;
		if (mHttpDiskCache != null) {
			try {
				DiskLruCache.Snapshot snapshot = mHttpDiskCache.get(ImageCache
						.hashKeyForDisk(data.getSourceCacheKey()));
				fileInputStream = (FileInputStream) snapshot
						.getInputStream(DISK_CACHE_INDEX);

				FileDescriptor fileDescriptor = fileInputStream.getFD();
				return decodeSampledBitmapFromDescriptor(fileDescriptor,
						data.getWidth(), data.getHeight(), getImageCache());
			} catch (Exception e) {
			} finally {
				if (fileInputStream != null) {
					try {
						fileInputStream.close();
					} catch (IOException e) {
					}
				}
			}
		}
		return null;
	}

	private Bitmap processFileBitmap(LoadImageFile data) {
		String localPath = data.getLocalPath();
		File file = new File(localPath);
		Bitmap bitmap = null;
		if (file.isFile()) {
			bitmap = saveFileBimtapToCache(data, file);

			if (bitmap == null || bitmap.isRecycled()) {
				bitmap = getFileBitmap(data, file);
			}

			int angle = BitmapUtils.readPictureDegree(localPath);
			if (angle > 0) {
				bitmap = BitmapUtils.rotaingImageView(angle, bitmap);
			}
		}
		return bitmap;
	}

	private Bitmap saveFileBimtapToCache(LoadImageFile data, File file) {
		FileInputStream fileInputStream = null;
		try {
			String key = ImageCache.hashKeyForDisk(data.getSourceCacheKey());
			if (data.isCacheStoregeAvailable()) {
				DiskLruCache.Editor editor = mHttpDiskCache.edit(key);
				if (editor != null) {
					if (fileToStream(file,
							editor.newOutputStream(DISK_CACHE_INDEX))) {
						editor.commit();
					} else {
						editor.abort();
					}
				}
				DiskLruCache.Snapshot snapshot = mHttpDiskCache.get(key);

				fileInputStream = (FileInputStream) snapshot
						.getInputStream(DISK_CACHE_INDEX);
				FileDescriptor fileDescriptor = fileInputStream.getFD();
				return decodeSampledBitmapFromDescriptor(fileDescriptor,
						data.getWidth(), data.getHeight(), getImageCache());
			}
		} catch (Exception ex) {
			Log.e(TAG, "Failed to saveFileBimtapToCache", ex);
		} finally {
			if (fileInputStream != null) {
				try {
					fileInputStream.close();
				} catch (IOException e) {
				}
			}
		}
		return null;
	}

	private Bitmap getFileBitmap(LoadImageFile data, File file) {
		FileInputStream fileInputStream = null;
		try {
			fileInputStream = new FileInputStream(file);
			FileDescriptor fileDescriptor = fileInputStream.getFD();
			return decodeSampledBitmapFromDescriptor(fileDescriptor,
					data.getWidth(), data.getHeight(), getImageCache());
		} catch (Exception ex) {
			Log.e(TAG, "Failed to getFileBitmap", ex);
		} finally {
			if (fileInputStream != null) {
				try {
					fileInputStream.close();
				} catch (IOException e) {
				}
			}
		}
		return null;
	}

	private Bitmap processUrlBitmap(LoadImageUrl data, Callback callback) {
		String url = data.getDownloadUrl(mTokenCallback);
		MyLog.d(TAG, "imagecache manager ................  url:" + url);
		Bitmap bitmap = null;
		if (url != null) {
			try {
				bitmap = saveUrlBitmapToCache(data, url, callback);
				if (bitmap == null || bitmap.isRecycled()) {
					bitmap = getUrlBitmap(data, url);
				}
			} catch (Throwable e) {
				Log.e(TAG, "Failed to processUrlBitmap " + data, e);
				return null;
			}
		}
		return bitmap;
	}

	private Bitmap saveUrlBitmapToCache(LoadImageUrl data, String url,
			Callback callback) throws SocketTimeoutException {
		if (data.isSmallUrl()) {
			return null;
		}
		FileInputStream fileInputStream = null;
		try {
			String key = ImageCache.hashKeyForDisk(data.getSourceCacheKey());
			DiskLruCache.Editor editor = mHttpDiskCache.edit(key);
			if (editor != null) {
				if (downloadUrlToStream(url,
						editor.newOutputStream(DISK_CACHE_INDEX), data,
						callback)) {
					editor.commit();
				} else {
					editor.abort();
				}
			}
			DiskLruCache.Snapshot snapshot = mHttpDiskCache.get(key);
			fileInputStream = (FileInputStream) snapshot
					.getInputStream(DISK_CACHE_INDEX);
			FileDescriptor fileDescriptor = fileInputStream.getFD();
			return decodeSampledBitmapFromDescriptor(fileDescriptor,
					data.getWidth(), data.getHeight(), getImageCache());
		} catch (SocketTimeoutException socketException) {
			throw socketException;
		} catch (Exception ex) {
			MyLog.e(TAG, "httpFrame saveFileBimtapToCache  ");
			Log.e(TAG, "Failed to saveUrlBitmapToCache " + data, ex);
		} finally {
			if (fileInputStream != null) {
				try {
					fileInputStream.close();
				} catch (IOException e) {
				}
			}
		}
		return null;
	}

	/**
	 * @param url
	 * @param file
	 */
	public void addCacheToStorage(String url, File file) {
		synchronized (mHttpDiskCacheLock) {
			// Wait for disk cache to initialize
			while (mHttpDiskCacheStarting) {
				try {
					mHttpDiskCacheLock.wait();
				} catch (InterruptedException e) {
				}
			}

			if (mHttpDiskCache != null && file.isFile()) {
				final String key = ImageCache.hashKeyForDisk(url);
				OutputStream out = null;
				try {
					DiskLruCache.Snapshot snapshot = mHttpDiskCache.get(key);
					if (snapshot == null) {
						final DiskLruCache.Editor editor = mHttpDiskCache
								.edit(key);
						if (editor != null) {
							if (fileToStream(file,
									editor.newOutputStream(DISK_CACHE_INDEX))) {
								editor.commit();
							} else {
								editor.abort();
							}
						}
					} else {
						snapshot.getInputStream(DISK_CACHE_INDEX).close();
					}
				} catch (final IOException e) {
					MyLog.e(TAG, "httpFrame addBitmapToCache - " + e);
				} catch (Exception e) {
					MyLog.e(TAG, "httpFrame addBitmapToCache - " + e);
				} finally {
					try {
						if (out != null) {
							out.close();
						}
					} catch (IOException e) {
					}
				}
			}
		}
	}

	private Bitmap getUrlBitmap(LoadImageUrl data, String urlString) {
        disableConnectionReuseIfNecessary();
        HttpURLConnection urlConnection = null;
        InputStream is = null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            is = urlConnection.getInputStream();
            byte[] bmData = Tools.inputStream2ByteArrary(is);
            Bitmap bmBitmap =  BitmapFactory.decodeByteArray(bmData, 0, bmData.length);
            return bmBitmap;
        } catch (final IOException e) {
            Log.e(TAG, "Failed to getUrlBitmap " + data, e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
}